﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using SedionFormDesigner.Service;
using System.ComponentModel.Design;

namespace SedionFormDesigner.Infrastructure
{
    /// <summary>
    ///  对属性值的事件方法的封装
    /// </summary>
    public class EventPropertyDescriptor : PropertyDescriptor
    {
        private SedionEventBindingService eventSvc;
        // 提供事件相关的信息
        private EventDescriptor eventDesc;
        private TypeConverter converter;

        internal EventPropertyDescriptor(EventDescriptor eventDesc, SedionEventBindingService eventSvc)
            : base(eventDesc, null)
        {
            this.eventDesc = eventDesc;
            this.eventSvc = eventSvc;
        }

        /// <summary>
        ///  获得事件相关信息
        /// </summary>
        internal EventDescriptor Event
        {
            get
            {
                return eventDesc;
            }
        }

        public override TypeConverter Converter
        {
            get
            {
                if (converter == null)
                    converter = new EventConverter(eventDesc);
                return converter;
            }
        }

        // 返回组件的类型
        public override Type ComponentType
        {
            get
            {
                return eventDesc.ComponentType;
            }
        }

        /// <summary>
        ///  判断是否为只读
        /// </summary>
        public override bool IsReadOnly
        {
            get
            {
                return Attributes[typeof(ReadOnlyAttribute)].Equals(ReadOnlyAttribute.Yes);
            }
        }

        /// <summary>
        ///  返回当前属性的类型
        /// </summary>
        public override Type PropertyType
        {
            get
            {
                return eventDesc.EventType;
            }
        }

        // 重置组件的值
        public override bool CanResetValue(object component)
        {
            return GetValue(component) != null;
        }

        // 获得组件当前属性的值
        public override object GetValue(object component)
        {
            if (component == null)
                throw new ArgumentNullException("component");

            ISite site = null;
            if (component is IComponent)
                site = ((IComponent)component).Site;

            if (site == null)
            {
                // 按名称或类型获得对项目内对象的引用,名称,父对象...
                IReferenceService refService = eventSvc.Provider.GetService(typeof(IReferenceService)) as IReferenceService;
                if (refService != null)
                {
                    // 获得指定组件的组件
                    IComponent baseComponent = refService.GetComponent(component);
                    if (baseComponent != null)
                        site = baseComponent.Site;
                }
            }

            if (site == null)
            {
                throw new InvalidOperationException(String.Concat("There is no site fot component ", component.ToString(), "."));
            }

            IDictionaryService dictService = (IDictionaryService)site.GetService(typeof(IDictionaryService));
            if (dictService == null)
                throw new InvalidOperationException("Cannot find IDictionaryService.");

            return (String)dictService.GetValue(new ReferenceEventClosure(component, this));
        }

        /// <summary>
        ///  重置组件的值为null
        /// </summary>
        public override void ResetValue(object component)
        {
            SetValue(component, null);
        }

        /// <summary>
        ///  设置组件的值
        /// </summary>
        public override void SetValue(object component, object value)
        {
            if (IsReadOnly)
                throw new InvalidOperationException("Tried to set a read only event.");

            if (value != null && !(value is String))
                throw new ArgumentException(String.Concat("Cannont set to value ", value.ToString(), "."));

            String name = (String)value;
            if (name != null && name.Length == 0)
                name = null;

            // 获得基本地址信息
            // 如果可以获得reference服务那么就是基类的地址信息
            ISite site = null;
            if (component is IComponent)
                site = ((IComponent)component).Site;

            if (site == null)
            {
                // 获得引用服务
                IReferenceService refService = eventSvc.Provider.GetService(typeof(IReferenceService)) as IReferenceService;
                if (refService != null)
                {
                    IComponent baseComponent = refService.GetComponent(component);
                    if (baseComponent != null)
                        site = baseComponent.Site;
                }
            }

            if (site == null)
                throw new InvalidOperationException("Cannot find IDictionaryService");

            // 用来存储事件方法实际名称的地方
            IDictionaryService dictService = (IDictionaryService)site.GetService(typeof(IDictionaryService));
            if (dictService == null)
                throw new InvalidOperationException("Cannot find IDictionaryService");

            // 获得旧的方法名称,确保他们不同,然后继续
            ReferenceEventClosure key = new ReferenceEventClosure(component, this);
            String oldName = (String)dictService.GetValue(key);

            if (Object.ReferenceEquals(oldName, name))
                return;

            if (oldName != null && name != null && oldName.Equals(name))
                return;

            // 确保名称是真的验证无误
            if (name != null)
                eventSvc.ValidateMethodName(name);

            // 已经确保名称不同,
            // 获得ChangeService并执行提交
            IComponentChangeService chanService = (IComponentChangeService)site.GetService(typeof(IComponentChangeService));
            if (chanService != null)
            {
                try
                {
                    // 向组件通知正在发生更改
                    chanService.OnComponentChanging(component, this);
                }
                catch (CheckoutException cex)
                {
                    if (cex == CheckoutException.Canceled)
                        return;
                    throw;
                }
            }

            // 确保添加新方法成功
            // 再移除旧方法
            if (name != null)
                eventSvc.UseMethod(component, eventDesc, name);

            if (oldName != null)
                eventSvc.FreeMethod(component, eventDesc, oldName);

            dictService.SetValue(key, name);
            // 通知组件方法名已经更改
            if (chanService != null)
                chanService.OnComponentChanged(component, this, oldName, name);

            // 触发已经更改的事件
            OnValueChanged(component, EventArgs.Empty);
        }

        /// <summary>
        ///  Indicates whether the value of this property needs to be persisted. In
        ///  other words, it indicates whether the state of the property is distinct
        ///  from when the component is first instantiated. If there is a default
        ///  value specified in this PropertyDescriptor, it will be compared against the
        ///  property's current value to determine this.  If there is't, the
        ///  shouldPersistXXX method is looked for and invoked if found.  If both
        ///  these routes fail, true will be returned.
        ///
        ///  If this returns false, a tool should not persist this property's value.
        ///  不懂... 下次翻译......
        /// </summary>
        public override bool ShouldSerializeValue(object component)
        {
            return CanResetValue(component);
        }
    }
}
